#include <codex/os/trace.h>
namespace codex
{
	namespace os
	{
		void HaltProcess(void)
		{
			while (1){}
		}

		void TerminateProcess(void)
		{
			cdxTerminate();
		}

		trace::trace(int nDefaultLvl)
		{
			m_nTraceLvl = nDefaultLvl;
		}

		void trace::setTraceLvl(int nLvl)
		{
			// sanity check
			if (nLvl < TR_LVL_ALL)
				nLvl = TR_LVL_ALL;
			else if (nLvl > TR_LVL_NONE)
				nLvl = TR_LVL_NONE;

			m_nTraceLvl = nLvl;
		}

		/*
		void trace::outputTrace(tString const& str, ...)
		{
			static char sBuffer[TR_CHAR_MAX];

			// skip if level is above message
			if (m_nTraceLvl > TR_LVL_MESSAGE)
				return;

			cdxVa_List va;
			cdxVa_Start(va, str.c_str());
			cdxVSPrintf(sBuffer, str.c_str(), va);
			cdxVa_End(va);
			cdxPrintf("%s\n", sBuffer);
		}
		*/

		void trace::outputTrace(const char *sMsg, ...)
		{
			static char sBuffer[TR_CHAR_MAX];

			// skip if level is above message
			if (m_nTraceLvl > TR_LVL_MESSAGE)
				return;
			cdxVa_List va;
			cdxVa_Start(va, sMsg);
			cdxVSPrintf(sBuffer, sMsg, va);
			cdxVa_End(va);
			cdxPrintf("%s\n", sBuffer);

		}

		void trace::outputTrace(int nLvlID, const char *sMsg, ...)
		{
			static char sOutBuffer[TR_CHAR_MAX];
			const char* sLvl[] = { "", "  Info", "Message", "*Warning", "**Error", "***Fatal", "" };

			// validate lvl
			if (nLvlID < m_nTraceLvl)
				return;

			// sanity check
			int nLvl = nLvlID;

			if (nLvlID < TR_LVL_ALL)
				nLvl = TR_LVL_ALL;
			else if (nLvlID > TR_LVL_NONE)
				nLvl = TR_LVL_NONE;

			// build info
			cdxSPrintf(&sOutBuffer[0], "%s: ", sLvl[nLvl]);

			// va trinity :P
			cdxVa_List va;

			cdxVa_Start(va, sMsg);
			cdxVSPrintf(cdxStrchr(sOutBuffer, '\0'), sMsg, va);
			cdxVa_End(va);

			//print
			cdxPrintf("%s\n", sOutBuffer);

			// halt if FATAL
			if (nLvlID == TR_LVL_FATAL)
			{
				HaltProcess();
			}
		}
		void trace::outputTrace(int nLvlID, const char *sFile, int nLine, const char *sMsg, ...)
		{
			static char sBuffer[TR_CHAR_MAX];
			const char* sLvl[] = { "", "Info", "Message", "Warning", "ERROR", "FATAL", "" };

			// validate lvl
			if (nLvlID < m_nTraceLvl)
				return;

			// sanity check
			int nLvl = nLvlID;

			if (nLvlID < TR_LVL_ALL)
				nLvl = TR_LVL_ALL;
			else if (nLvlID > TR_LVL_NONE)
				nLvl = TR_LVL_NONE;

			// build info
			cdxSPrintf(sBuffer, "%s(%d): %s: ", sFile, nLine, sLvl[nLvl]);

			// trinity

			cdxVa_List va;

			cdxVa_Start(va, sMsg);
			cdxVSPrintf(strchr(sBuffer, '\0'), sMsg, va);
			cdxVa_End(va);

			//print
			cdxPrintf("%s\n", sBuffer);

			// halt if FATAL
			if (nLvlID == TR_LVL_FATAL)
			{
				HaltProcess();
			}
		}

		void trace::outputError(const char *sMsg, ...)
		{
			static char sBuffer[TR_CHAR_MAX];

			cdxVa_List va;
			// va trinity
			cdxVa_Start(va, sMsg);
			cdxVSPrintf(sBuffer, sMsg, va);
			cdxVa_End(va);

			//print
			cdxPrintf("%s\nExecution Terminated.", sBuffer);


			// terminate execution
			TerminateProcess();
		}
		void trace::outputError(const char *sFile, int nLine, const char *sMsg, ...)
		{
			static char sBuffer[TR_CHAR_MAX];

			// build info
			cdxSPrintf(sBuffer, ">>> %s(%d): PANIC: ", sFile, nLine);

			// va trinity
			cdxVa_List va;

			cdxVa_Start(va, sMsg);
			cdxVSPrintf(strchr(sBuffer, '\0'), sMsg, va);
			cdxVa_End(va);

			//print
			cdxPrintf("%s\nExecution Terminated.", sBuffer);

			// terminate execution
			TerminateProcess();
		}

		//===================================================================================================================
		//===================================================================================================================
		staticTrace* staticTrace::m_pInstance = NULL;

		staticTrace* staticTrace::get(void)
		{
			if (!m_pInstance)
			{
				m_pInstance = new staticTrace;
			}
			return m_pInstance;
		}

	}
}